package io.gitee.xjt2016.modules.controller;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import io.gitee.xjt2016.modules.common.BaseController;
import io.gitee.xjt2016.modules.common.utils.JsonLoop;
import io.gitee.xjt2016.modules.domain.*;
import io.gitee.xjt2016.modules.domain.vo.InterfaceVo;
import io.gitee.xjt2016.modules.service.FieldService;
import io.gitee.xjt2016.modules.service.FunctionService;
import io.gitee.xjt2016.modules.service.InterfaceService;
import io.gitee.xjt2016.modules.service.ProjectService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Controller
@RequestMapping(value = "/interface")
public class InterfaceController extends BaseController {

    public static final String module = "interface";
    public static final String pathPrefix = "/" + module;
    private static final String PARAM_KEY = "data";

    @Autowired
    InterfaceService service;

    @Autowired
    FunctionService functionService;

    @Autowired
    ProjectService projectService;

    @Autowired
    FieldService fieldService;

    @Autowired
    InterfaceService interfaceService;

    @ModelAttribute
    public void modelAttribute(Model model, HttpServletRequest request) {
        model.addAttribute("module", module);
        model.addAttribute("pathPrefix", pathPrefix);

        Map<String, ?> map = RequestContextUtils.getInputFlashMap(request);
        //model.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        if (map != null) {
            model.addAttribute("message", map.get("message") + "");
            model.addAttribute("code", map.get("code") + "");
        }

        List<Map<String, Object>> fieldDataTypes = Arrays.stream(FieldDataType.values()).map(fieldDataType -> {
            Map<String, Object> map1 = new HashMap<>();
            map1.put("value", fieldDataType.getValue());
            map1.put("text", fieldDataType.getName());
            return map1;
        }).collect(Collectors.toList());
        model.addAttribute("fieldDataTypes", fieldDataTypes);
    }

    @GetMapping(value = {"/index", ""})
    public String index() throws Exception {
        return pathPrefix + "/index";
    }

    public static final Snowflake snowflake = new Snowflake(0, 0);

    @ResponseBody
    @GetMapping(value = {"/nextId"})
    public Object nextId() throws Exception {
        return buildSuccessResponse(snowflake.nextId());
    }

    @GetMapping(value = {"/params"})
    public String params(Long id, Model model) throws Exception {
        Preconditions.checkNotNull(id);
        Interface anInterface = service.getInterface(id);
        Preconditions.checkNotNull(anInterface);
        model.addAttribute("anInterface", anInterface);
        return pathPrefix + "/params";
    }

    @ResponseBody
    @PostMapping(value = {"/params"})
    public Object params(String params, Long interfaceId, String type) throws Exception {
        Preconditions.checkNotNull(interfaceId);
        Preconditions.checkNotNull(type);
        FieldType fieldType = FieldType.valueOf(type);
        Preconditions.checkNotNull(fieldType);

        List<Field> fields = JSON.parseArray(params, Field.class);
        fields.forEach(field -> {
            field.setAnInterface(null);
            field.setInterfaceId(interfaceId);
            field.setType(type);
            field.setFid(field.getId());
            field.setId(null);
        });
        fieldService.saveByInterfaceIdAndType(fields, interfaceId, type);
        return buildSuccessResponse();
    }

    @ResponseBody
    @GetMapping(value = {"/getParams"})
    public Object data(InterfaceVo vo, Long id) throws Exception {
        List<Field> fields = fieldService.getFieldsByInterfaceId(id);
        fields.forEach(field -> field.setId(field.getFid()));
        return buildSuccessResponse(fields);
    }

    @ResponseBody
    @GetMapping(value = {"/getInterfaces"})
    public Object getInterfaces(Long projectId) throws Exception {
        Preconditions.checkNotNull(projectId);
        List<Function> functions = functionService.getFunctionByProjectId(projectId);
//        Set<Long> functionIds = functions.stream().map(new java.util.function.Function<Function, Long>() {
//            @Override
//            public Long apply(Function function) {
//                return function.getId();
//            }
//        }).collect(Collectors.toSet());
        functions.stream().forEach(function -> {
            List<Interface> interfaces = interfaceService.getInterfaceListByFunctionIds(Lists.newArrayList(function.getId()));
            function.setInterfaceList(interfaces);
        });
        return buildSuccessResponse(functions);
    }

    @ResponseBody
    @RequestMapping(value = {"/getList"})
    public Object getList(InterfaceVo vo) throws Exception {
        IPage<Interface> page = initMyBatisPage(vo);
        page = service.page(page, Wrappers.lambdaQuery(Interface.class));

        page.getRecords().forEach(anInterface -> {
            anInterface.setFunction(functionService.getFunction(anInterface.getFunctionId()));
        });

        return pageResponse(page);
    }

    @ResponseBody
    @PostMapping(value = "/importJson")
    public Object importJson(String json) {
        Preconditions.checkArgument(StringUtils.isNoneBlank(json));
        JSONObject jsonObject = new JSONObject();
        if (json.startsWith("[")) {
            JSONArray jsonArray = JSON.parseArray(json);
            Preconditions.checkArgument(jsonArray.size() > 0);
            jsonObject = (JSONObject) jsonArray.get(0);
        } else {
            jsonObject = JSON.parseObject(json);
        }
        return buildSuccessResponse(new JsonLoop().jsonLoop(jsonObject, 0L));
    }

    @ResponseBody
    @RequestMapping(value = {"/treeData"})
    public Object treeData() throws Exception {
        List<Function> functions = functionService.list();
        return functionService.list();
    }

    @GetMapping(value = {"/form"})
    public String formGet(Long id, Model model) throws Exception {
        Interface form = service.getInterface(id);
        if (form == null) {
            form = new Interface();
        }
        model.addAttribute(PARAM_KEY, form);
        return pathPrefix + "/form";
    }

    @PostMapping(value = {"/form"})
    public ModelAndView formPost(Interface form, RedirectAttributes attributes) throws Exception {
        boolean result = service.saveOrUpdate(form);
        attributes.addFlashAttribute("message", result);
        attributes.addFlashAttribute("code", 100);
        return buildRedirectModelAndView(pathPrefix);
    }

    @ResponseBody
    @GetMapping(value = {"/delete"})
    public ModelAndView delete(String id, RedirectAttributes attributes) throws Exception {
        boolean result = service.removeByIds(split2LongList(id));
        attributes.addFlashAttribute("message", result);
        attributes.addFlashAttribute("code", 100);
        return buildRedirectModelAndView(pathPrefix);
    }

}
